﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;
using Microsoft.Expression.Interactivity;
using System.Windows.Interactivity;
using Microsoft.Devices.Sensors;
using Microsoft.Xna.Framework;
using System.Windows.Threading;

namespace girapong
{

    // Object ball
    public class ball: solid
    {
        public System.Windows.Shapes.Ellipse circle { get; set; }

        public double BALL_DIAMETER = 30;
        public int restoreModule { get; set; }


        //Constructors
        public ball(rally pRally, System.Windows.Media.Color color, double x0, double y0, int m)
        {
            restoreModule = m;
            Vector2 startSpeed = general.generateRandomVectorByModule(m);
            speed = startSpeed;
            circle = new System.Windows.Shapes.Ellipse();
            circle.StrokeThickness = 3;
            circle.Fill = new SolidColorBrush(color);
            circle.VerticalAlignment = System.Windows.VerticalAlignment.Top;
            circle.HorizontalAlignment = System.Windows.HorizontalAlignment.Left;
            setPosition(new System.Windows.Point(x0, y0));
            circle.Width = BALL_DIAMETER;
            circle.Height = BALL_DIAMETER;
            pRally.LayoutRoot.Children.Add(circle);
            rallyReference = pRally;
            dtSpeed = new DispatcherTimer();
            setColor(System.Windows.Media.Color.FromArgb(255, 0, 0, 255));
        }

        public ball(screen pPantalla, System.Windows.Media.Color color, double x0, double y0, int m)
        {
            restoreModule = m;
            Vector2 velocidadInicial = general.generateRandomVectorByModule(m);
            speed = velocidadInicial;
            circle = new System.Windows.Shapes.Ellipse();
            circle.StrokeThickness = 3;
            circle.Fill = new SolidColorBrush(color);
            circle.VerticalAlignment = System.Windows.VerticalAlignment.Top;
            circle.HorizontalAlignment = System.Windows.HorizontalAlignment.Left;
            setPosition(new System.Windows.Point(x0, y0));
            circle.Width = BALL_DIAMETER;
            circle.Height = BALL_DIAMETER;
            pPantalla.LayoutRoot.Children.Add(circle);
            screenReference = pPantalla;
            dtSpeed = new DispatcherTimer();
            setColor(System.Windows.Media.Color.FromArgb(255, 0, 0, 255));
        }

        /// <summary>
        /// Set speed and timer both to change the module and the direction of the vector as well
        /// </summary>
        /// <param name="velocidad">Vector2 speed</param>
        public void setSpeed(Vector2 speed)
        {
            dtSpeed.Interval = TimeSpan.FromMilliseconds(1); //Convert.ToInt32(Math.Ceiling(1000/speed.Length())));
            dtSpeed.Tick += new EventHandler(this.refreshBall);
            changeSpeed(speed);
        }
        /// <summary>
        /// Set speed´s ball for the rally mode
        /// </summary>
        /// <param name="speed"></param>
        public void setRally(Vector2 speed)
        {
            dtSpeed.Interval = TimeSpan.FromMilliseconds(1);
            dtSpeed.Tick += new EventHandler(this.refreshRally);
            changeSpeed(speed);
        }
        /// <summary>
        /// Set the module maintaining the same direction
        /// </summary>
        /// <param name="velocidad"></param>
        public void changeSpeed(Vector2 speed)
        {
            this.speed = speed;
        }

        /// <summary>
        /// Set the position
        /// </summary>
        /// <param name="p"></param>
        public void setPosition(System.Windows.Point p)
        {
            position = p;
            circle.Margin = new Thickness(position.X, position.Y, 0, 0);
        }
        public void setColor(System.Windows.Media.Color color)
        {
            circle.Stroke = new SolidColorBrush(color);
        }
        /// <summary>
        /// Start movement
        /// </summary>
        public void playMovement()
        {
            dtSpeed.Start();
        }
        /// <summary>
        /// Stop movement
        /// </summary>
        public void stopMovement()
        {
            dtSpeed.Stop();
        }

        public void refreshBall(object sender, EventArgs e)
        {
            Vector2 vUnitary = new Vector2(speed.X, speed.Y);

            if (speed.X != 0) position.X += vUnitary.X;
            if (speed.Y != 0) position.Y += vUnitary.Y;
            circle.Margin = new Thickness(position.X, position.Y, 0, 0);

            enemy en = screenReference._barEnemy;
            System.Windows.Shapes.Rectangle rE = en._bar.rectangle;
            System.Windows.Shapes.Rectangle rU = screenReference._barPlayer.rectangle;
            if ((screenReference.turn == 1) && rectangleIntersection(rE)) //golpe cpu
            {
                float increaseX, increaseY;

                increaseX = screenReference.enemyStrenght;
                increaseY = screenReference.enemyStrenght;
                double vABSX = Math.Abs(increaseX);
                double vABSY = Math.Abs(increaseY);
                if (vABSX <= 5 * vABSY)
                {
                    increaseX += 2;
                    increaseY--;
                }
                else if (vABSY <= 5 * vABSX)
                {
                    increaseY += 2;
                    increaseX--;
                }
                if (speed.X <= 0) increaseX = -increaseX;
                if (speed.Y <= 0) increaseY = -increaseY;
                if (speed.X <= 5 * speed.Y)
                {
                    increaseX += 2;
                    increaseY--;
                }
                else if (speed.Y <= 5 * speed.X)
                {
                    increaseY += 2;
                    increaseX--;
                }

                if ((en.reachedEdge == 1) || (en.reachedEdge == 3))
                {

                    changeSpeed(new Vector2(speed.X + increaseX, -(speed.Y + increaseY)));
                }
                else
                {
                    changeSpeed(new Vector2(-(speed.X + increaseX), speed.Y + increaseY));
                }
                screenReference.turn = 0;
                setColor(System.Windows.Media.Color.FromArgb(255, 0, 0, 255));
            }
            else
            {
                if ((screenReference.turn == 0) && rectangleIntersection(rU))  //bump user
                {
                    float increaseX, increaseY;
                    increaseX = 0;
                    increaseY = 0;
                    double vABSX = Math.Abs(increaseX);
                    double vABSY = Math.Abs(increaseY);
                    if (vABSX <= 5 * vABSY)
                    {
                        increaseX += 2;
                        increaseY--;
                    }
                    else if (vABSY <= 5 * vABSX)
                    {
                        increaseY += 2;
                        increaseX--;
                    }
                    if ((screenReference.userEdge == 1) || (screenReference.userEdge == 3))
                    {
                        double variacion = screenReference.vectorDifference().Length() * 10;
                        if (speed.X < 0) variacion = -(variacion + increaseX);
                        changeSpeed(new Vector2((float)(speed.X + variacion), -(speed.Y + increaseY)));
                    }
                    else
                    {
                        double variacion = screenReference.vectorDifference().Length() * 10;
                        if (speed.Y < 0) variacion = -(variacion + increaseY);
                        if (speed.X < 0) increaseX = -increaseX;
                        changeSpeed(new Vector2(-(speed.X + increaseX), speed.Y + (float)(variacion + speed.Y)));
                    }
                    screenReference.turn = 1;
                    setColor(System.Windows.Media.Color.FromArgb(255, 255, 0, 0));
                }
                else
                {
                    if (screenReference.blockList != null) //bump block
                    {
                        List<SolidBlock> lista = screenReference.blockList;
                        if (lista.Count > 0)
                        {
                            foreach (SolidBlock b in lista)
                            {
                                System.Windows.Shapes.Rectangle r = b.shape;
                                if ((circle.Margin.Left <= r.Margin.Left) || (circle.Margin.Left > (r.Margin.Left + r.Width)))
                                {
                                    changeSpeed(new Vector2(-speed.X, speed.Y));
                                    break;
                                }
                                else if ((circle.Margin.Top <= r.Margin.Top) || (circle.Margin.Top > (r.Margin.Top + r.Height)))
                                {
                                    changeSpeed(new Vector2(speed.X, -speed.Y));
                                    break;
                                }
                            }
                        }
                    }
                    else // add score or top/bottom bump
                    {
                        if ((position.X <= -bar.HEIGHT_DEFAULT) || (position.X >= screen.HEIGHT))
                        {
                            setPosition(new System.Windows.Point(screen.HALFHEIGHT, screen.HALFWIDTH));
                            changeSpeed(general.generateRandomVectorByModule(this.restoreModule));
                            if (screenReference.turn == 0)
                            {
                                screenReference.killOneLife();
                                screenReference.turn = 1;
                                setColor(System.Windows.Media.Color.FromArgb(255, 255, 0, 0));
                            }
                            else
                            {
                                screenReference.addOneScorePoint();
                                screenReference.turn = 0;
                                setColor(System.Windows.Media.Color.FromArgb(255, 0, 0, 255));
                            }
                        }
                        if ((position.Y <= 0) || (position.Y + circle.Width >= screen.WIDTH))
                        {
                            changeSpeed(new Vector2(speed.X, -speed.Y));
                        }
                    }

                }
            }
        }
        public void refreshRally(object sender, EventArgs e)
        {
            Vector2 vUnitary = new Vector2(speed.X, speed.Y);
            if (speed.X != 0) position.X += vUnitary.X;
            if (speed.Y != 0) position.Y += vUnitary.Y;
            circle.Margin = new Thickness(position.X, position.Y, 0, 0);
            System.Windows.Shapes.Rectangle rU = rallyReference._barPlayer.rectangle;
            if (rectangleIntersection(rU))
            {
                rallyReference.score++;
                explode();
            }
            else
            {
                if ((circle.Margin.Left <= 0) || (circle.Margin.Left+rallyReference.barraDcha.Width+circle.Width >= screen.WIDTH))
                {
                    changeSpeed(new Vector2(-speed.X, speed.Y));
                }
                else if (circle.Margin.Top <= 0)
                {
                    changeSpeed(new Vector2(speed.X, -speed.Y));
                }
                else
                {
                    if ((circle.Margin.Top + circle.Width) >= screen.HEIGHT)
                    {
                        if (speed.Y > 0)
                        {
                            rallyReference.numLifes--;
                            rallyReference.txtVidas.Text = rallyReference.numLifes.ToString();
                            if (rallyReference.numLifes > 0)
                            {
                                split();
                            }
                            else rallyReference.gameover();
                        }
                    }
                    else if (rallyReference.blockList != null)
                    {
                        List<SolidBlock> lista = rallyReference.blockList;
                        if (lista.Count > 0)
                        {
                            for (int i = 0; i < lista.Count; i++)
                            {
                                System.Windows.Shapes.Rectangle r = lista[i].shape;

                                double circuloSubTop= circle.Margin.Top - 15;
                                double circuloBottom = circle.Margin.Top + circle.Height;
                                double circuloRight = circle.Margin.Left + circle.Width;
                                double rRight = r.Margin.Left+r.Width;
                                double rBottom = r.Margin.Top + r.Height;

                                if (base.clashToBlockWhileMovement(circle.Margin.Left, circle.Width, circle.Margin.Top, circle.Height, r) == 0)
                                {
                                    changeSpeed(new Vector2(speed.X, -speed.Y));
                                    break;
                                }
                                else
                                    if (base.clashToBlockWhileMovement(circle.Margin.Left, circle.Width, circle.Margin.Top, circle.Height, r) == 1)
                                    {
                                        changeSpeed(new Vector2(-speed.X, speed.Y));
                                    }
                            }
                        }
                    }
                }
            }
        }

        // Ball is splitted in two miniballs
        public void split()
        {
            if (rallyReference.ballList.Count <= 20)
            {
                ball p = new ball(rallyReference, System.Windows.Media.Color.FromArgb(255, 255, 0, 0), circle.Margin.Left, circle.Margin.Top, 1);
                Vector2 v = general.generateRandomOnBottomArrowVectorByModule(2);
                v.Y = -speed.Y;
                p.circle.Width /= 2;
                p.circle.Height /= 2;
                p.setRally(v);
                rallyReference.ballList.Add(p);
                p.playMovement();
                Vector2 w = new Vector2(-v.X, v.Y);
                ball p2 = new ball(rallyReference, System.Windows.Media.Color.FromArgb(255, 255, 0, 0), circle.Margin.Left, circle.Margin.Top, 1);
                p2.circle.Width /= 2;
                p2.circle.Height /= 2;
                p2.setRally(w);
                p2.playMovement();
                rallyReference.ballList.Add(p2);
            }
            explode();
        }

        public void explode()
        {
            rallyReference.txtPuntuacionPeloteo.Text = rallyReference.score.ToString();
            rallyReference.nextLife--;
            if (rallyReference.nextLife == 0)
            {
                rallyReference.nextLife = 10;
                rallyReference.numLifes++;
                rallyReference.txtVidas.Text = rallyReference.numLifes.ToString();
            }
            rallyReference.txtSiguienteVida.Text = rallyReference.nextLife.ToString();
            stopMovement();
            dtSpeed = new DispatcherTimer();
            dtSpeed.Interval = TimeSpan.FromMilliseconds(1);
            dtSpeed.Tick += new EventHandler(explosion);
            dtSpeed.Start();
        }
        public void explosion(object sender, EventArgs e)
        {
            circle.Width -= 1;
            circle.Height -= 1;
            circle.Fill = new SolidColorBrush(System.Windows.Media.Color.FromArgb(125, 255, 125, 125));
            if (circle.Width <= 0)
            {
                rallyReference.numBalls--;
                stopMovement();
                if (circle != null)
                {
                    rallyReference.LayoutRoot.Children.Remove(circle);
                    rallyReference.ballList.Remove(this);
                }
            }
        }
        public Boolean rectangleIntersection(System.Windows.Shapes.Rectangle rE)
        {
            Thickness margen = circle.Margin;
            return base.rectangleIntersection(margen.Left, circle.Width, margen.Top, circle.Height, rE);
        }
    }
}
